﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////


#pragma once
#include "GnufBase.h"
#include "GnufBaseUtils.h"

class QFont;
class QWidget;
class QColor;
class QPixmap;
class QPushButton;
class QString;

namespace gnuf {
    class ArrangementArea;
    class ArrangementAreaContent;
    class Color;
    class Toolbar;
    class QtWindow;
    class Item;
    class RootItem;

    class GNUF_BASE_EXPORT Utility
    {
    public:
        static void splitString(
            const std::string & str,
            const char delimiter,
            std::vector<std::string> & parts);

        static void splitWString(
            const std::wstring & str,
            const wchar_t delimiter,
            std::vector<std::wstring> & parts);

        static std::wstring& trim(std::wstring&);

        template <typename TObject>
        static void destroyInstance(TObject * ptr)
        {
            if (nullptr != ptr) {
                gcmp::OwnerPtr<TObject>(ptr).reset();
            }
        }

        /// \brief 清理垃圾桶。
        ///        用于Ui(延迟删除)关闭后，应用程序关闭前,清理掉暂时还未来的及删除的Ui对象，
        ///        防止Ui对象在程序栈退出后还未清理，造成异常。
        /// \return void
        static void ClearTrashBin();

        static void setQtWidgetParent(ArrangementAreaContent *);
        static void setQtWidgetParent(const ArrangementArea *, ArrangementAreaContent *);
        static void refreshQtWidgetGeometry(ArrangementAreaContent *, bool bMust = false);
        static void refreshQtWidgetGeometry(const ArrangementArea *,
            ArrangementAreaContent *, bool bMust = false);
        static QWidget * latestQtWidget(const ArrangementArea *);
        static bool posAtLatestQtWidget(const ArrangementArea *, int & x, int & y);

        static void calculate(
            const QFont &, const std::wstring & , int & width, int & height);

        static void setFont(QWidget *);
        static void setBackground(QWidget *, const QColor &);
        static void setBackground(QWidget *, const Color &);
        static void setBackgroundRepeat(QWidget*, const std::wstring&, double scale = 1.0);
        static void setTextColor(QWidget*, const QColor&);

        static const gcmp::UniqueString * extractClassNameFrom(const char * constructor);

        static bool setExecutingCommand(const std::wstring &, bool, const gcmp::UniqueString* location);
        static bool isExecutingCommand();

        static void refreshStatus(bool immediately = false);

        static std::wstring convertPixmapToWString(const QPixmap& pixmap);
        static QPixmap convertWStringToPixmap(const std::wstring& bytes);

        static void refreshToolbarAppearance(Toolbar*);

        static void refreshAppearance(RootItem*);

        static bool addApplicationCustomizeFont(const std::wstring& fontPath);
        
        // For pushButton size
        static const int        s_leftButtonMargin;
        static const int        s_topButtonMarginForSmall;
        static const int        s_topButtonMarginForMedium;
        static const int        s_topButtonMarginForBig;
        static const int        s_rightButtonMargin;
        static const int        s_bottomButtonMarginForSmall;
        static const int        s_bottomButtonMarginForMedium;
        static const int        s_bottomButtonMarginForBig;
        static const int        s_minimumLengthOfButtonContent;
        static const int        s_minimumCountOfButtonContent;

        enum class GnufButtonSize : std::uint8_t
        {
            eSmallButton,
            eMediumButton,
            eBigButton
        };

        static void setSmallButton(QPushButton* pushButton);
        static void setMediumButton(QPushButton* pushButton);
        static void setBigButton(QPushButton* pushButton);
        static void setButtonSize(QPushButton* pushButton, const QString& text, GnufButtonSize buttonSize);

        // Show the top QWidget in the screen.
        static void moveIntoScreen(QWidget *);

        static std::wstring appDataLocalApplicationDirPath();

        // Get the scale factor from the QWidget and return it.
        static gnuf::ScaleFactor getScaleFactorFrom(const QWidget *);

        // Get the Qt window from the arrangement area.
        static gnuf::QtWindow * getQtWindowFrom(const ArrangementArea *);

        /// \brief Show the tooltip for the item around the QWidget.
        /// \return Return true if showing, otherwise return false.
        /// \param pItem is the pointer to the item.
        /// \param qtWgt is the pointer to the QWidget. If null, use the item's QtItem, instead.
        static bool showTooltip(const Item * pItem, const QWidget * pQtWgt = nullptr);
    };

    template <class TQtWidget>
    class QtWidgetShared
    {
    protected:
        QtWidgetShared() : m_refCount(0) {}
        virtual ~QtWidgetShared()
        {
            DBG_WARN_UNLESS(
                0 == m_refCount &&
                nullptr == m_qtWidget.get(),
                L"", L"fangkunfk", L"");
        }        
    public:
        const TQtWidget * qtWidget() const { return m_qtWidget.get(); }
              TQtWidget * qtWidget()       { return m_qtWidget.get(); }

        int refCount() const { return m_refCount; }

        void addRef()
        {
            ++m_refCount;

            if (nullptr == m_qtWidget.get())
            {
                m_qtWidget = onMakeQtWidget();
            }
        }

        void removeRef()
        {
            if (m_refCount < 1)
                return;

            --m_refCount;

            if (0 == m_refCount)
            {
                m_qtWidget->setParent(nullptr);
                onDestroyQtWidget();
            }
        }
    protected:
        virtual gcmp::OwnerPtr< TQtWidget > onMakeQtWidget() const = 0;
        virtual void onDestroyQtWidget()
        {
            if(TQtWidget* pWgt = m_qtWidget.ReleaseOwnership())
                pWgt->deleteLater();
        }
    private:
        gcmp::OwnerPtr< TQtWidget > m_qtWidget;
        int m_refCount;
    };
}
